package packing.treeSearch;

import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet;
import it.unimi.dsi.fastutil.objects.ObjectSortedSet;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;

import cloning.Cloner;

import Comparator.BlockVolumeComparator;

import packing.*;


public class CLTRS {
	
	public static int max_bl = 10000;
	public static double min_fr=0.98;
	public static int min_ns = 3;
	public static int search_effort =1;
	public Packer packer = new Packer();
	public Cloner cloner = new Cloner();
	public static State stmp;
	public static State ptmpbest;
	public static State pbest;
	
	public CLTRS() {
		super();
	}
	
	public void solve(State currentState){
		
		ObjectSortedSet<Block> blockSet = new ObjectRBTreeSet<Block>(new BlockVolumeComparator());
		blockSet.addAll(packer.getFitableBlock(currentState, currentState.getEmptySpaceStack().peek(0), true, min_fr));
		Calendar cal = Calendar.getInstance();
		cal.getTime().getTime();

		for(int i =0 ; i<1;i++){
			while(!currentState.getEmptySpaceStack().isEmpty()){
				
			}
			search_effort= search_effort*2;
		}
	}
	public List<Block> getBestBlock(State state, boolean simpleOnly){
		Packer packer = new Packer(state);
		EmptySpace emptySpace = state.getEmptySpaceStack().pop();
		List<Block> blockList = packer.getFitableBlock(state, emptySpace, simpleOnly, min_fr);
		if(blockList.size()==0 && blockList.size()==1)return blockList;
		int total_add_block = Math.max(1, (int)(search_effort/min_ns));
		
//		State ptmpbest = state;
		
		List<int [] > orderPartitionList =generateOrderPartition(total_add_block);
		for(int [] orderParition : orderPartitionList  ){
//			State stmpbest =state;
			for(int i =0; i<orderParition.length;i++){
//				int ns = Math.max(min_ns, (int)(search_effort/orderParition[i]));
			}
		}
		return null;
	}	
//	
	public List<Node<State>> getChild (Node<State> state, int no_succ, List<Block> blockList){
		List<Node<State>> childList = new ObjectArrayList<Node<State>>();
		State dummieState = cloner.deepClone(state.getData());
		List<Block> Bll_rs;
		EmptySpace emptySpace;
		do{
			emptySpace = dummieState.getEmptySpaceStack().pop();
			System.out.println(emptySpace);
			Bll_rs= generate_rs_blocklist(dummieState,emptySpace , no_succ, blockList);
//			System.out.println(Bll_rs.size());
		}while(Bll_rs.isEmpty() && !dummieState.getEmptySpaceStack().isEmpty());

		for(Block block : Bll_rs){
			State childState = cloner.deepClone(dummieState);
			EmptySpaceBlockPair pair = new EmptySpaceBlockPair(emptySpace, block);
			packer.pack(childState, pair);
			childList.add(new Node<State>(childState));
		}
//		System.out.println(childList.size());
		return childList;

	}
	public void extendSolution (Node<State> state,int no_add_block, int no_succ, List<Block> blockList){
		if(no_add_block!=0){
			state.addAllChild(getChild(state, no_succ, blockList));
			for(Node<State> childState : state.getChildren()){
				extendSolution(childState, no_add_block-1, no_succ, blockList);				
			}
		}
	}
	
	public List<Block> generate_rs_blocklist(State state, EmptySpace emptySpace, int no_succ, List<Block> blockList){
		int found = 0;
		int index=blockList.size();
		List<Block> result = new ObjectArrayList<Block>();
		while(found<no_succ &&index>0){
			Block block = blockList.get(index-1);

			if(block.getWidth()<= emptySpace.getWidth()
					&& block.getLength()<= emptySpace.getLength()
					&& block.getHeight() <= emptySpace.getHeight()){
				if(state.isValidBlock(block)){
					result.add(block);
					found++;
				}
			}
			index--;
		}
		return result;
	}
	
	public State complete_solution(State state2complete, boolean simpleOnly, double blockPercentage) {
		Packer packer = new Packer();
		do{
			EmptySpace emptySpace = state2complete.getEmptySpaceStack().pop();
			List<Block> fitBoxList = packer.getFitableBlock(state2complete, emptySpace, simpleOnly, blockPercentage);
			if(fitBoxList.size()>0){
				Collections.sort(fitBoxList, new BlockVolumeComparator());
				EmptySpaceBlockPair pair = new EmptySpaceBlockPair(emptySpace, fitBoxList.get(fitBoxList.size()-1));
				state2complete = packer.pack(state2complete, pair);
			}
			
			
		}while(!state2complete.getEmptySpaceStack().isEmpty());
		return state2complete;
	}
	
	public List<int[]>combination (int limit, int layer){
		if(layer==1){
			List<int []> result = new ArrayList<int[]>();
		
			for(int i =1; i<= limit;i++){
				result.add(new int[]{i});
			}
			return result;			
		}else{
			int [] tupe = new int [limit];
			for(int i =1; i<= limit;i++){
				tupe[i-1]=i;
			}
			List<int []> previous = combination(limit, layer-1);
			List<int []> result = new ArrayList<int[]>();
			for(int i =0; i < tupe.length; i++){
				for(int [] oldTupe : previous){
					int [] newTupe = new int[oldTupe.length+1];
					System.arraycopy(oldTupe, 0, newTupe, 0, oldTupe.length);
					newTupe[newTupe.length-1]= tupe[i];
					result.add(newTupe);
				}				
			}
			return result;
		}		
	}
	
	public List<int[]> generateOrderPartition(int total_add_block){
		List<int[]> resultOrderPartition = new ArrayList<int[]>();
		for(int i=1; i<=total_add_block;i++){
			List<int []> result = combination(total_add_block, i);
			for(int [] tupe : result){
				int sum =0;
				for(int j =0; j<tupe.length;j++){
					sum+= tupe[j];
				}
				if(sum==total_add_block)resultOrderPartition.add(tupe);
			}
		}
		return resultOrderPartition;		
	}
}
